package com.yeziji.dynamicConfig.service.impl;

import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.yeziji.dynamicConfig.base.ConfigMeta;
import com.yeziji.dynamicConfig.base.EnvironmentFactory;
import com.yeziji.dynamicConfig.msg.DynamicConfigErrorMsg;
import com.yeziji.dynamicConfig.service.ConfigService;
import com.yeziji.utils.expansion.Asserts;
import com.yeziji.utils.expansion.Lists2;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.origin.OriginTrackedValue;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 程序文件配置实现类
 *
 * @author hwy
 * @since 2023/12/13 10:18
 **/
@Slf4j
public class AppConfigServiceImpl extends EnvironmentFactory implements ConfigService {

    public AppConfigServiceImpl(boolean printLog) {
        super(printLog);
    }

    @Override
    public boolean update(ConfigMeta configMeta) {
        Meta meta = this.getFilterMeta(configMeta.getEnv(), configMeta.getKey());
        if (meta.hasAppName()) {
            final String appName = meta.getAppName();
            Map<String, Object> configMap = meta.getConfigMap();
            configMap.put(configMeta.getKey(), OriginTrackedValue.of(configMeta.getValue()));
            ENVIRONMENT.getPropertySources()
                    .replace(appName, new OriginTrackedMapPropertySource(appName, configMap));
            return true;
        }
        return false;
    }

    @Override
    public boolean delete(ConfigMeta configMeta) {
        Meta meta = this.getFilterMeta(configMeta.getEnv(), configMeta.getKey());
        if (meta.hasAppName()) {
            final String appName = meta.getAppName();
            ENVIRONMENT.getPropertySources()
                    .replace(appName, new OriginTrackedMapPropertySource(appName, meta.getConfigMap()));
            return true;
        }
        return false;
    }

    @Override
    public ConfigMeta get(String key) {
        List<ConfigMeta> configMeta = super.getConfigMeta();
        Map<String, ConfigMeta> configMap = Lists2.streamToMap(configMeta, ConfigMeta::getKey);
        return Asserts.notNull(configMap.get(key), DynamicConfigErrorMsg.CONFIG_IS_NOT_EXISTS);
    }

    @Override
    public List<ConfigMeta> listAll() {
        return super.getConfigMeta();
    }

    public Meta getFilterMeta(String env, String filterKey, String... filterKeys) {
        List<String> list = Lists.asList(filterKey, filterKeys).stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());

        List<ConfigMeta> configMetas = super.getConfigMeta();
        Map<String, List<ConfigMeta>> appConfigs =
                Lists2.streamToGroupBy(configMetas, ConfigMeta::getEnvStr);
        String appName = null;
        Map<String, Object> newConfigMap = new HashMap<>();
        List<ConfigMeta> appConfigMetas = appConfigs.get(env);
        if (Lists2.isNotEmpty(appConfigMetas)) {
            for (ConfigMeta meta : appConfigMetas) {
                if (appName == null) {
                    appName = meta.getEnv();
                }
                if (list.contains(meta.getKey())) {
                    continue;
                }
                newConfigMap.put(meta.getKey(), meta.getValue());
            }
        }
        return new Meta(env, appName, newConfigMap);
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private static class Meta {
        private String env;

        private String appName;

        private Map<String, Object> configMap;

        public boolean hasAppName() {
            return StrUtil.isNotBlank(this.appName);
        }
    }
}
